#ifndef _OS_H_  
#define _OS_H_  
/**
 * \file os.h
 * \brief A simple RTOS interface  
 * \b Note: Please don't edit the interface file "os.h".
 *
 * \author Dr. Mantis Cheng
 * \date 26 September 2007
 */
   
/*==================================================================  
 *             T Y P E S   &   C O N S T A N T S  
 *==================================================================  
 */  

/*================
  *    C O N S T A N T S
  *================
  */
/* limits */

/** max. number of processes supported */  
#define MAXPROCESS     8       

/** max. number of Events supported */
#define MAXEVENT	8

/** workspace size of each process in bytes */  
#define WORKSPACE      256   

/** milliseconds, or something close to this value 
 * \sa \ref periodic.
 */
#define TICK                    5        

/* scheduling levels */

/** a scheduling level: system tasks with first-come-first-served policy 
 * \sa \ref system, Task_Create().
 */
#define SYSTEM            3 

/** a scheduling level: periodic tasks with predefined intervals 
 * \sa \ref periodic, Task_Create().
 */
#define PERIODIC            2 

/** A scheduling level: first-come-first-served cooperative tasks
 * \sa \ref rr, Task_Create(). 
 */
#define RR                   1      

//Changed because of conflict with <string.h>
#ifndef NULL  
	#define NULL     0   /* undefined */
#endif /* NULL */

#define IDLE     0   /* a well-known PERIODIC task name */

/*================
  *    T Y P E S
  *================
  */
/** An Event descriptor
 * \sa Event_Init().
 */
typedef struct event EVENT;  

/*================
  *    G L O B A L S
  *================
  */
 /**
   *  A periodic task scheduling plan (read-only, defined by the application).
   *
   *  This is specified by the application. The scheduling ordering and duration 
   *  of all PERIODIC tasks are specified by this plan. The total number of
   *  occurrences of all PERIODIC tasks, including IDLE, is given by PT.
   *  e.g., PPP[] = { A, 2, IDLE, 5, B, 1, A, 2, C, 4 };
   *        PT = 5; 
   *  \sa \ref periodic.
   */


extern const unsigned char PPP[]; 
extern const unsigned int PT;
  
/*==================================================================  
 *             A C C E S S    P R O C E D U R E S  
 *==================================================================  
 */  

  /*=====  OS   Initialization ===== */

/** Initialize this RTOS; must be called first. 
 * \sa \ref boot.
 */
void OS_Init(void);

/** Abort the execution of this RTOS due to an unrecoverable erorr.
 * \sa \ref assumptions. 
 */
void OS_Abort(void);  

  /*=====  Task API ===== */

 /**
   * \param f  a parameterless function to be created as a process instance
   * \param arg an integer argument to be assigned to this process instanace
   * \param level assigned scheduling level: SYSTEM, PERIODIC or RR
   * \param name assigned PERIODIC process name
   * \return 0 if not successful; otherwise non-zero.
   * \sa Task_GetArg(), PPP[].
   *
   *  A new process  is created to execute the parameterless
   *  function \a f with an initial parameter \a arg, which is retrieved
   *  by a call to Task_GetArg().  If a new process cannot be
   *  created, 0 is returned; otherwise, it returns non-zero.
   *  The created process will belong to its scheduling \a level.
   *  If the process is PERIODIC, then its \a name is a user-specified name 
   *  to be used in the PPP[] array. Otherwise, \a name is ignored. 
   * \sa \ref policy
   */
int   Task_Create(void (*f)(void), int arg, unsigned int level, unsigned int name);

/** 
 * Terminate the calling process
 *
 *  When a process returns, i.e., it executes its last instruction in 
 *  the associated function/code, it is automatically terminated.
 */
void Task_Terminate(void);    

/** Voluntarily relinquish the processor. */
void Task_Next(void);              

/** Retrieve the assigned parameter. 
  * \sa Task_Create(). 
  */
int Task_GetArg(void);          

  /*=====  Events API ===== */

/**
 * \return a non-NULL Event descriptor if successful; NULL otherwise.
 *
 *  Initialize a new, non-NULL Event descriptor.
 */
EVENT *Event_Init(void);

/**  
  * \param e  an Even descriptor
  *
  * Wait for the next occurrence of a signal on \a e. The calling process always blocks. 
  */
void Event_Wait( EVENT *e );  

/**  
  * \param e an Event descriptor
  *
  * Resume a \b single waiting task on \a e. It is a \a no-op if there is no waiting process.
  * \sa Event_Wait() 
  */
void Event_Signal( EVENT *e );

/**  
  * \param e  an Event descriptor
  *
  * Resume \b ALL waiting tasks on \a e. It is a \a no-op if there is no waiting process. 
  * \sa Event_Wait()
  */
void Event_Broadcast( EVENT *e );

   
/**  
  * \param e  an Event descriptor
  *
  * Resume a waiting task on \a e and at the same time relinquish the processor.
  * This is equivalent to "Event_Signal( e ); Task_Next()" in concept. The
  * fundamental difference is that these two operations are performed as
  * an indivisible unit. So conceptually, the calling task resumes another
  * waiting task and gives up its share of the processor simultaneously.
  * \sa Event_Signal(), Task_Next()
  */
void  Signal_And_Next( EVENT *e );
   
/**  
  * \param e  an Event descriptor
  *
  * Resume \b ALL waiting tasks on \a e and at the same time relinquish the processor.
  * This is equivalent to "Event_Broadcast( e ); Task_Next()" in concept.
  * \sa Event_Broadcast(), Task_Next()
  */
void  Broadcast_And_Next( EVENT *e );

#endif /* _OS_H_ */
